home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / comm / ytsg3.zip / FMF.C < prev    next >
C/C++ Source or Header  |  1993-05-05  |  36KB  |  835 lines

  1. /************************************************/
  2. /* Author: G.R. Blair                           */
  3. /*         BOBBLAIR @ AUSVM1                    */
  4. /*         bobblair@bobblair.austin.ibm.com     */
  5. /*                                              */
  6. /* The following code is property of            */
  7. /* International Business Machines Corporation. */
  8. /*                                              */
  9. /* Copyright International Business Machines    */
  10. /* Corporation,1990,1991.  All rights reserved. */
  11. /************************************************/
  12.  
  13. /*-----------------------------------------------------------------------*/
  14. /* Modification History:                                                 */
  15. /*      Release 1       5/1/91                                           */
  16. /*  @1  05/03/91 Scott Emmons reported grep did not work on network      */
  17. /*               drives.  Found out that I was assuming the archive bit. */
  18. /*  @2  05/07/91 The logic was far worse than I thought.  Besides these  */
  19. /*               file selection changes, 6 users of fmf_init also have   */
  20. /*               to change.  There's a corequisite fix to fmf.h.         */
  21. /*  @3  05/10/91 Still another glitch:  selection logic was wrong,       */
  22. /*               sending directories to pgms that didn't ask for them.   */
  23. /*  @4  04/13/93 Added conditional compilation for 16-bit toolkit        */
  24. /*-----------------------------------------------------------------------*/
  25.  
  26. /* This may turn out to be a callable utility for programs that need to        *
  27. *  find one or more files that match an ambiguous file spec.                   *
  28. *                                                                              *
  29. *  This version is NOT thread-tolerant.  Use fmfmt.c for code that exploits    *
  30. *  threads.                                                                    *
  31. *                                                                              *
  32. *  There are three entry points:                                               *
  33. *      int fmf_init(char *pattern, unsigned fmfmask, int fmfmode)                    *
  34. *                              which initializes a search for the caller.      *
  35. *                              The mode is 0 for specified directory           *
  36. *                              only, or 1 for search-everything-below.         *
  37. *                                                                              *
  38. *             NOTE: Having the ARCHIVED bit on means that you want        @1@2 *
  39. *                   files that do not have one of the other four          @2   *
  40. *                   attributes (DIRECTORY, HIDDEN, SYSTEM, READONLY).     @2   *
  41. *                   If the ARCHIVED bit is off, then the file will not    @2   *
  42. *                   selected unless it has one of the other attributes    @2   *
  43. *                   listed above, and you have requested that attribute.  @2   *
  44. *                   I've tried to simplify this by making equates in fmf.h@2   *
  45. *                                                                              *
  46. *                                                                              *
  47. *      int fmf_return_next( char *where_to_put_name, int *where_put_attribute )*
  48. *                              which returns a pointer to a file name and  its *
  49. *                              attributes that satisfies the pattern.  The     *
  50. *                              returned is qualified relative to the name and  *
  51. *                              path specified in the pattern.  For example, if *
  52. *                              the pattern was "C:\OS2\*.EXE then the first    *
  53. *                              name returned might be "C:\OS2\ANSI.EXE"; a     *
  54. *                              later one might be                              *
  55. *                              "C:\OS2\INSTALL\CIKSTART.EXE"                   *
  56. *                                                                              *
  57. *      fmf_close()             which frees resources reserved for the caller   *
  58. *                              It doesn't have to be used.                     *
  59. */
  60.  
  61.  
  62. #include <stdlib.h>
  63. #include <stdio.h>
  64. #include <io.h>
  65. #include <string.h>
  66. #include <ctype.h>
  67. #include "fmf.h"                                     // @2
  68. #define INCL_BASE
  69. #include <os2.h>
  70.  
  71. #define ALLF "*.*"
  72. #define chBACKSLASH  '\\'
  73. #define achBACKSLASH "\\"
  74. #define chCOLON      ':'
  75. #define chDOT        '.'
  76. #define achDOT       "."
  77. #define achDOTDOT    ".."
  78. #define YES  1
  79. #define NO   0
  80.                               /*----------------------------------------------*/
  81.                               /* Declare how many concurrent threads we are   */
  82.                               /* willing to handle                            */
  83.                               /*----------------------------------------------*/
  84. #define MAX_THREADS_HERE 12
  85.                               /*----------------------------------------------*/
  86.                               /* structure that describes the context         */
  87.                               /* information for each thread                  */
  88.                               /*----------------------------------------------*/
  89. typedef struct _context  {
  90.                   HDIR    dhandle;
  91.                   char    *path;
  92.                   struct _context *BackPointer;
  93.                 } CONTEXT;
  94.                               /*----------------------------------------------*/
  95.                               /*  Semephore to serialize access to globals    */
  96.                               /*----------------------------------------------*/
  97. ULONG   fmfSem = 0;
  98.                               /*----------------------------------------------*/
  99.                               /* variables global to fmf                      */
  100.                               /*----------------------------------------------*/
  101. CONTEXT        *current_context;
  102. char           *namespec, *matchspec;
  103. char            drivespec;
  104. int             fmfmode;
  105. unsigned        fmfmask;
  106. #ifdef I16
  107. FILEFINDBUF     ffb;
  108. #else
  109. FILEFINDBUF3    ffb;
  110. #endif
  111. char            NameWkArea[CCHMAXPATH];
  112. char           *allfs = "*.*";
  113.                               /*----------------------------------------------*/
  114.                               /* The private routines                         */
  115.                               /*----------------------------------------------*/
  116. void AssembleName(char *where);
  117. void AssemblePath(char *where);
  118. int  wcmatch(char *string1, char *string2);
  119.                               /*----------------------------------------------*/
  120.                               /* Prototype for the error-message formatter,   */
  121.                               /* which is external                            */
  122.                               /*----------------------------------------------*/
  123. void myerror(int rc, char *area, char *details);
  124.  
  125. /*----------------------------------------------------------------------------*/
  126. /*    fmf_init                                                                */
  127. /*                                                                            */
  128. /* Find-matching-files initialization routine.  The user passes the pattern   */
  129. /* and the search mode (0 or 1).  This routine sets up the data areas needed  */
  130. /* to find and match the files.                                               */
  131. /*----------------------------------------------------------------------------*/
  132. int fmf_init(char *filespec, unsigned srchmask, int srchmode)
  133. {
  134.  
  135.        int     rc, pathlen;                                           /* @4c */
  136. #ifdef I16                                                            /* @4a */
  137.        int     srchcnt;                                               /* @4a */
  138. #else                                                                 /* @4a */
  139.        unsigned long srchcnt;                                         /* @4a */
  140. #endif                                                                /* @4a */
  141.        HDIR    handle1 = 1;
  142.        CONTEXT *cp;
  143.        char    *p, *fnstart, *pathstart;
  144.        char    LocalWkArea[CCHMAXPATH];
  145.        void    fmf_close(void);
  146.  
  147. #ifdef DEBUG
  148. printf("fmf_init - into the routine\n");
  149. #endif
  150.  
  151.        if (current_context != 0)
  152.          fmf_close();
  153.        current_context = 0;
  154.        namespec = 0;
  155.        drivespec = '\0';
  156.        fmfmode = 0;
  157.        fmfmask = 0;
  158.  
  159.        if (!(cp = (CONTEXT *)malloc(sizeof(CONTEXT))) )
  160.          {
  161. //            perror("fmf_init malloc of context");
  162.             myerror(ERROR_NOT_ENOUGH_MEMORY, "fmf_init", "malloc of context");
  163.             return(-2);
  164.          }
  165.        current_context = cp;
  166.        cp->BackPointer = 0;
  167.        cp->path = 0;
  168.        cp->dhandle = -1;
  169.  
  170.        fmfmode = srchmode;
  171. //       fmfmask = srchmask;                             // @1
  172.        fmfmask = 0;                                      // @2
  173.        if (srchmask == -1)                               // @2
  174.          fmfmask = FMF_ALL_DIRS_AND_FILES;               // @2
  175.        else                                              // @2
  176.          if (srchmask == 0)                              // @2
  177.            fmfmask = FMF_FILES;                          // @2
  178.          else                                            // @2
  179.            fmfmask = srchmask;                           // @2
  180.  
  181. #ifdef DEBUG
  182. printf("Search mode = %d\n", srchmode);
  183. #endif
  184.                                  /*-------------------------------------------*/
  185.                                  /* There are a couple of quirks in filespecs */
  186.                                  /* that we need to worry about.  First, a    */
  187.                                  /* spec that consists only of the drive des- */
  188.                                  /* ignation must be modified to have a path; */
  189.                                  /* we do that by appending a dot.  Second,   */
  190.                                  /* a spec that ends in a backslash is impli- */
  191.                                  /* citly a directory, so we should append    */
  192.                                  /* *.*. Dot directories get a name of *.*,   */
  193.                                  /* too.                                      */
  194.                                  /*-------------------------------------------*/
  195.        cp->dhandle = -1;
  196.        strcpy (NameWkArea, filespec); /* get the filespec where we can chg it*/
  197.        p = NameWkArea;
  198.        if (NameWkArea[1] == chCOLON) /* Is drive specified? If so, capture it */
  199.          {
  200.            drivespec = *p;
  201.            p += 2;
  202.          }
  203.        pathstart = p;
  204.        if (!*p)                   /* Was only the drive specified, or nothing?*/
  205.          strcat(NameWkArea, achDOT);   /* Put in the assumed dot */
  206.                                   /* If "\" terminates spec, add *.*          */
  207.        for (p = NameWkArea; *p; p++);
  208.        --p;
  209.        if (*p == chBACKSLASH)
  210.          strcat(NameWkArea, allfs);
  211.                                  /*-------------------------------------------*/
  212.                                  /* Do DosFindFirst on the path to make sure  */
  213.                                  /* it exists.                                */
  214.                                  /*-------------------------------------------*/
  215.        srchcnt = 1;
  216.        rc = DosFindFirst(NameWkArea,
  217.                          &handle1,
  218.                          FILE_SYSTEM | FILE_HIDDEN | FILE_DIRECTORY,
  219.                          &ffb,
  220. #ifdef I16
  221.                          sizeof(FILEFINDBUF),
  222. #else
  223.                          sizeof(FILEFINDBUF3),
  224. #endif
  225.                          &srchcnt,
  226. #ifdef I16
  227.                          0l);
  228. #else
  229.                          1l);
  230. #endif
  231. #ifdef DEBUG
  232. printf("First DosFindFirst on %s returned %d\n", filespec, rc);
  233. #endif
  234.                                  /*-------------------------------------------*/
  235.                                  /* If the first FindFirst fails, the caller  */
  236.                                  /* may mean "all files with this name in the */
  237.                                  /* specified directory or lower".  If so, we */
  238.                                  /* look at all the files and throw out the   */
  239.                                  /* ones we don't want.                       */
  240.                                  /*-------------------------------------------*/
  241.        if ( (rc != NO_ERROR) && (fmfmode == 1) )
  242.          {
  243.            strcpy(LocalWkArea, NameWkArea);
  244.            if ( (p = strrchr(pathstart, chBACKSLASH)) )
  245.              fnstart = LocalWkArea + (p - NameWkArea + 1);
  246.            else
  247.              fnstart = LocalWkArea + (pathstart - NameWkArea);
  248.            strcpy(fnstart, allfs);
  249.            handle1 = 1;
  250.            srchcnt = 1;
  251.            rc = DosFindFirst(LocalWkArea,
  252.                              &handle1,
  253.                              FILE_SYSTEM | FILE_HIDDEN | FILE_DIRECTORY,
  254.                              &ffb,
  255. #ifdef I16
  256.                              sizeof(FILEFINDBUF),
  257. #else
  258.                              sizeof(FILEFINDBUF3),
  259. #endif
  260.                              &srchcnt,
  261. #ifdef I16
  262.                              0l);
  263. #else
  264.                              1l);
  265. #endif
  266. #ifdef DEBUG
  267. printf("Second DosFindFirst on %s returned %d\n", LocalWkArea, rc);
  268. #endif
  269.          }
  270.  
  271.        if ( rc != NO_ERROR)
  272.          {
  273.            free(cp);
  274.            current_context = 0;
  275.            drivespec = '\0';
  276.            return(rc);
  277.          }
  278.                                  /*-------------------------------------------*/
  279.                                  /* Find the start of the name part of the    */
  280.                                  /* path specification.  It's either the part */
  281.                                  /* after the last backslash, the part after  */
  282.                                  /* the colon, or the whole thing.            */
  283.                                  /*-------------------------------------------*/
  284.  
  285.        if ( (p = strrchr(pathstart, chBACKSLASH)) )
  286.          fnstart = p + 1;
  287.        else
  288.          fnstart = pathstart;
  289. #ifdef DEBUG
  290. printf("Name within input spec is %s, in ffb %s\n", fnstart, ffb.achName);
  291. #endif
  292.                                  /*-------------------------------------------*/
  293.                                  /* If the path has been specified 'shorthand'*/
  294.                                  /* by just naming the directory, put a *.*   */
  295.                                  /* on the end.                               */
  296.                                  /*-------------------------------------------*/
  297.        if ((ffb.attrFile & FILE_DIRECTORY) && /* FindFirst yields a directory */
  298.            (stricmp(fnstart, ffb.achName)==0)) /*with same name as file sought*/
  299.          {
  300.            namespec = allfs;                      /* *.* implied              */
  301.            matchspec = allfs;
  302.          }
  303.        else                                     /* Just \ specified as path */
  304.          if ( (strcmp(pathstart, achBACKSLASH) == 0) ||
  305.               (*fnstart == chDOT) )             /* or a dot directory named */
  306.            {
  307.              namespec = allfs;                    /* Also implies *.*         */
  308.              matchspec = allfs;
  309.            }
  310.          else                                 /* A file object was specified */
  311.            {
  312.              if (strcmp(fnstart, allfs) == 0) /* If it wasn't *.* */
  313.                {
  314.                  namespec = allfs;
  315.                  matchspec = allfs;
  316.                }
  317.              else                             /*    allocate some space for it*/
  318.                if ( (namespec = (char *)malloc(strlen(fnstart) + 1)) )
  319.                  {
  320.                    strcpy(namespec, fnstart);
  321.                    if (fmfmode != 0)        /* if subtree search specified */
  322.                      {
  323.                        matchspec = namespec;  /* use alloc space for match nm*/
  324.                        namespec = allfs;      /* we will look at everything */
  325.                      }
  326.                  }
  327.                else
  328.                  {
  329.                    free(cp);
  330.                    current_context = 0;
  331.                    drivespec = '\0';
  332. //                   perror("fmf_init malloc of path");
  333.                    myerror(ERROR_NOT_ENOUGH_MEMORY, "fmf_init", "malloc of path");
  334.                    return(-2);
  335.                  }
  336.              if (fnstart - pathstart > 1)     /* back up to the backslash    */
  337.                --fnstart;                     /* unless it's the root        */
  338.              *fnstart = '\0';       /* and overlay it to mark end of path     */
  339.            }
  340.        pathlen = strlen(pathstart);
  341.        if (pathlen)
  342.          if ((cp->path = (char *)malloc(pathlen + 1)) )
  343.            strcpy(cp->path, pathstart);
  344.          else
  345.            {
  346.               if (namespec != allfs)
  347.                 free(namespec);
  348.               free(cp);
  349.               current_context = 0;
  350. //              perror("fmf_init malloc of path");
  351.               myerror(ERROR_NOT_ENOUGH_MEMORY, "fmf_init", "malloc of path");
  352.               return(-2);
  353.            }
  354.        else
  355.          cp->path = 0;
  356.  
  357.  
  358. #ifdef DEBUG
  359. AssembleName(NameWkArea);
  360. printf("Reassembled input file spec: %s\n", NameWkArea);
  361. #endif
  362.  
  363.        return(NO_ERROR);
  364. }
  365.  
  366.  
  367. /*----------------------------------------------------------------------------*/
  368. /*    fmf_query_max_threads                                                   */
  369. /*                                                                            */
  370. /* Returns an integer reporting the number of concurrently-active threads are */
  371. /* suported by the fmf routines.  An 'active' thread is one who has made an   */
  372. /* fmf_init() call since its last call to fmf_close().                        */
  373. /*----------------------------------------------------------------------------*/
  374. int fmf_query_max_threads()
  375. {
  376.    return(1);
  377. }
  378.  
  379. /*----------------------------------------------------------------------------*/
  380. /*   fmf_close                                                                */
  381. /*                                                                            */
  382. /* Removes the current thread from the list of active threads.  Deallocates   */
  383. /* any resources devoted to context for the thread.  A thread that has issued */
  384. /* an fmf_init call should call this routine before it exits.                 */
  385. /*----------------------------------------------------------------------------*/
  386. void fmf_close()
  387. {
  388.        CONTEXT *CurrContext, *NextContext;
  389.  
  390.        CurrContext = current_context;
  391.        do
  392.          {
  393.            if (namespec != allfs)
  394.              free(namespec);
  395.            else
  396.              if ( (matchspec != allfs) && (fmfmode == 1) )
  397.                free(matchspec);
  398.            drivespec = '\0';
  399.            if (CurrContext->path)
  400.              free(CurrContext->path);
  401.            NextContext = CurrContext->BackPointer;
  402.            free(CurrContext);
  403.            CurrContext = NextContext;
  404.          }    while (CurrContext);
  405.        current_context = 0;
  406.        namespec = 0;
  407.        matchspec = 0;
  408.  
  409. }
  410.  
  411. /*----------------------------------------------------------------------------*/
  412. /*    fmf_return_next                                                         */
  413. /*                                                                            */
  414. /* Return a code of NO_ERROR, along with the name of the next file that       */
  415. /* matches the pattern specified in fmf_init; or return a code of             */
  416. /* ERROR_NO_MORE_FILES to indicate that there are no more files in the path   */
  417. /* that match the pattern; or return a code indicating an error occured.      */
  418. /*----------------------------------------------------------------------------*/
  419. int fmf_return_next(char *CopyNameTo, int *CopyAttrTo)
  420. {
  421.        CONTEXT *cp;
  422.        int rc;                                                         /* @4c */
  423. #ifdef I16                                                             /* @4a */
  424.        int srchcnt;                                                    /* @4a */
  425. #else                                                                  /* @4a */
  426.        unsigned long srchcnt;                                          /* @4a */
  427. #endif                                                                 /* @4a */
  428.  
  429.        int fmfProcess(int *rc, char *NameTo, int *AttrTo);
  430.  
  431.        if  (current_context)
  432.          while (1)
  433.            {
  434.              cp = current_context;
  435.              srchcnt = 1;
  436. #ifdef DEBUG
  437. printf("fmf_next: dhandle is %d\n", cp->dhandle);
  438. #endif
  439.  
  440.              if (cp->dhandle == -1)              /* No FindFirst yet */
  441.                {
  442.                  AssembleName(NameWkArea);
  443. #ifdef DEBUG
  444. printf("fnf_next FindFirst name is %s\n", NameWkArea);
  445. #endif
  446.                  rc = DosFindFirst(NameWkArea,
  447.                                    &(cp->dhandle),
  448.                                    FILE_SYSTEM | FILE_HIDDEN | FILE_DIRECTORY,
  449. //                                   fmfmask | FILE_DIRECTORY,
  450.                                    &ffb,
  451. #ifdef I16
  452.                                    sizeof(FILEFINDBUF),
  453. #else
  454.                                    sizeof(FILEFINDBUF3),
  455. #endif
  456.                                    &srchcnt,
  457. #ifdef I16
  458.                                    0l);
  459. #else
  460.                                    1l);
  461. #endif
  462.                }
  463.              else                               /* FindFirst already done */
  464.                  rc = DosFindNext( cp->dhandle,
  465.                                    &ffb,
  466. #ifdef I16
  467.                                    sizeof(FILEFINDBUF),
  468. #else
  469.                                    sizeof(FILEFINDBUF3),
  470. #endif
  471.                                    &srchcnt);
  472. #ifdef DEBUG
  473. printf("rc from DosFind* was %d\n", rc);
  474. #endif
  475.  
  476.              if (fmfProcess(&rc, CopyNameTo, CopyAttrTo))
  477.                return(rc);
  478.            }
  479.  
  480.        return(NO_ERROR);
  481. }
  482.  
  483.  
  484.  
  485. /*----------------------------------------------------------------------------*/
  486. /*  fmfProcess                                                                */
  487. /*                                                                              */
  488. /* Handle the logic that required to decide whether to return a file name,    */
  489. /* to look for another one in the current search, or to start a new search    */
  490. /* context.  The logic is common after either a FindFirst or a FindNext       */
  491. /*----------------------------------------------------------------------------*/
  492.  
  493. int fmfProcess(int *ReturnCode, char *PutFileName, int *PutAttr)
  494. {
  495.      CONTEXT *cp, *sBP, *newcp;
  496.      int     rc, pathlen, new_context;
  497.  
  498. #ifdef DEBUG
  499. printf("fmfProcess - into routine\n");
  500. #endif
  501.  
  502.      cp = current_context;
  503.      rc = *ReturnCode;   /* return code from DosFindFirst or DosFindNext */
  504.                               /*----------------------------------------------*/
  505.                               /* If a system error occured, or the path was   */
  506.                               /* bad, exit.                                   */
  507.                               /*----------------------------------------------*/
  508.      if (rc != NO_ERROR)
  509.        {
  510.          if (rc != ERROR_NO_MORE_FILES)
  511.            {
  512. //             perror("fmf_next DosFindFirst");
  513.              myerror(rc, "fmf_next", "DosFindFirst");
  514.              *ReturnCode = rc;
  515.              return(YES);    /* we want the error returned to fmf caller */
  516.            }
  517. #ifdef DEBUG
  518. printf("fmfProcess - no more files. ");
  519. #endif
  520.                               /*----------------------------------------------*/
  521.                               /* If the path is good, but there are no        */
  522.                               /* matching file names, go back to previous     */
  523.                               /* context, or exit if we are on top level      */
  524.                               /*----------------------------------------------*/
  525.          DosFindClose(cp->dhandle);
  526.          if ((sBP = cp->BackPointer) != 0)  /* there is a higher context */
  527.            {
  528.              if (cp->path)
  529.                free(cp->path);
  530.              free(cp);
  531.              current_context = sBP;
  532.              *ReturnCode = (NO_ERROR);
  533. #ifdef DEBUG
  534. printf("Restored previous context\n");
  535. #endif
  536.              return(NO);      /* we don't want to return to fmf caller */
  537.            }
  538.          else                               /* we're at the highest context */
  539.            {
  540.              cp->dhandle = -1;
  541.              *ReturnCode = rc;
  542. #ifdef DEBUG
  543. printf("Already at top-level context\n");
  544. #endif
  545.              return(YES);
  546.            }
  547.        }
  548.                               /*----------------------------------------------*/
  549.                               /* If DosFind*     completed successfully, look */
  550.                               /* at the file returned.                        */
  551.                               /*                                              */
  552.                               /* If the file found is a legitimate member of  */
  553.                               /* the family of files requested, check if it's */
  554.                               /* a directory.  If so, either ignore it or     */
  555.                               /* create a new context to handle it.           */
  556.                               /*----------------------------------------------*/
  557. #ifdef DEBUG
  558. printf("fmfProcess: Good return of name %s\n", ffb.achName);
  559. #endif
  560.  
  561.      if ( (strcmp(ffb.achName, achDOT) == 0) ||
  562.           (strcmp(ffb.achName, achDOTDOT) == 0) )
  563.        {
  564.          *ReturnCode = NO_ERROR;
  565. #ifdef DEBUG
  566. printf("fmfProcess: Skipped dot directory %s\n", ffb.achName);
  567. #endif
  568.          return(NO);  /* we want to skip over dot directories */
  569.        }
  570.  
  571.      new_context = NO;
  572.      if ((ffb.attrFile & FILE_DIRECTORY))
  573.        if (fmfmode == 1)       /* We are walking subdirectories */
  574.          {                         /* create a new context */
  575.            if ( (newcp = (CONTEXT *)malloc(sizeof(CONTEXT))) == 0)
  576.              {  // perror("fmf_process malloc of context");
  577.                 myerror(ERROR_NOT_ENOUGH_MEMORY, "fmf_process", "malloc of context");
  578.                 return(-2);
  579.              }
  580.  
  581.            newcp->dhandle = -1;
  582.            newcp->BackPointer = cp;
  583.            pathlen = 2;
  584.            if (cp->path)
  585.              pathlen += strlen(cp->path);
  586.            pathlen += strlen(ffb.achName);
  587.            if ( (newcp->path = (char *)malloc(pathlen)) == 0)
  588.              {
  589.               free(newcp);
  590. //               perror("fmf_process malloc of path");
  591.                myerror(ERROR_NOT_ENOUGH_MEMORY, "fmf_process", "malloc of path");
  592.                *ReturnCode = -2;
  593.                return(YES);
  594.              }
  595.            *(newcp->path) = '\0';
  596.            if (cp->path)
  597.              {
  598.                strcpy(newcp->path, cp->path);
  599.                if (strcmp(cp->path, achBACKSLASH) != 0)
  600.                  strcat(newcp->path, achBACKSLASH);
  601.              }
  602.            strcat(newcp->path, ffb.achName);
  603.            current_context = newcp;
  604.            new_context = YES;
  605. #ifdef DEBUG
  606. printf("fmfProcess: created new context, path = %s\n", newcp->path);
  607. #endif
  608.          }
  609.                               /*----------------------------------------------*/
  610.                               /* If its    attributes indicate it's one on the*/
  611.                               /* files the caller wants to see, return it     */
  612.                               /*----------------------------------------------*/
  613. #ifdef DEBUG
  614. printf("Search mask: %x  attribute: %x  fmfmode: %d\n", fmfmask, ffb.attrFile, fmfmode);
  615. #endif
  616.      *ReturnCode = NO_ERROR;
  617.      if (fmfmode == 1)   /* if we are walking subtrees, we return all files, so */
  618.                            /* see it this one's name matches the spec */
  619.        {
  620.          if (wcmatch(matchspec, ffb.achName) == 0)
  621.            {
  622. #ifdef DEBUG
  623. printf("File name %s did not match input spec %s\n", ffb.achName, matchspec);
  624. #endif
  625.              return(NO);          /* if not, skip it */
  626.            }
  627.        }
  628.  
  629. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@2 */
  630. /* The rules for accepting a file based on its attributes are these:    @2 */
  631. /*  1 If the FILE_HIDDEN, FILE_READONLY, FILE_DIRECTORY,                @2 */
  632. /* FILE_SYSTEM or FILE_ARCHIVED bit was ON in the request mask, and     @2 */
  633. /* the corresponding attribute belongs to the file,                     @2 */
  634. /*          ACCEPT the file                                             @2 */
  635. /*  2 Otherwise, if the ARCHIVED bit is on                              @2 */
  636. /*          ACCEPT the file if it is normal or archived-only            @2 */
  637. /*  3 Otherwise, REJECT the file                                        @2 */
  638. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@2 */
  639.     rc = YES;
  640.     if ((fmfmask & FMF_DIRS_AND_FILES) != FMF_DIRS_AND_FILES) /* if we can  @3*/
  641.       if ( (fmfmask & FMF_DIRS) != (ffb.attrFile & FILE_DIRECTORY) )
  642.         rc = NO;
  643.     if (rc == YES)
  644.       if (!(fmfmask & FMF_ALLMARK))      /* can we weed on basis of attrib? */
  645.         if (( fmfmask & FMF_SYSTEM) != (ffb.attrFile & FILE_SYSTEM)  ||
  646.             ( fmfmask & FMF_READONLY) != (ffb.attrFile & FILE_READONLY) ||
  647.             ( fmfmask & FMF_HIDDEN) != (ffb.attrFile & FILE_HIDDEN) )
  648.            rc = NO;
  649. //     if (fmfmask & ffb.attrFile)                                          @1
  650. //     if ( (fmfmask & ffb.attrFile) || (fmfmask == ffb.attrFile) ||       // @1
  651. //          ( (fmfmask == FILE_NORMAL) && (ffb.attrFile == FILE_ARCHIVED) ) )@2
  652. //          ( (fmfmask | ffb.attrFile) == FILE_ARCHIVED) )                 // @2
  653.  
  654. //     rc = NO;                                                           //  @2
  655. //     if (fmfmask & ffb.attrFile)                     // Rule 1              @2
  656. //       rc = YES;                                                        //  @2
  657. //     else                                                               //  @2
  658. //       if (fmfmask & FILE_ARCHIVED))                 // Rule 2              @2
  659. //         if (ffb.attrFile == FILE_NORMAL || ffb.attrFile == FILE_ARCHIVED)//@2
  660. //           rc = YES;                                                    //  @2
  661.  
  662.      if (rc == YES)                                                     //  @2
  663.        {
  664.          AssemblePath(PutFileName);
  665.          if (!new_context)
  666.            {
  667.              if (cp->path)
  668.                if (strcmp(cp->path, achBACKSLASH) != 0)
  669.                  strcat(PutFileName, achBACKSLASH);
  670.              strcat(PutFileName, ffb.achName);
  671.            }
  672.          *PutAttr = ffb.attrFile;
  673.          return(YES);
  674.        }
  675.      else
  676.        {
  677.          return(NO);
  678. #ifdef DEBUG
  679. printf("fmfProcess: Skipped %s %s\n", (ffb.attrFile & FILE_DIRECTORY) ?
  680.                                            "Subdirectory" : "File",
  681.                                        ffb.achName);
  682. #endif
  683.        }
  684.      return(YES);
  685. }
  686.  
  687.  
  688. /*----------------------------------------------------------------------------*/
  689. /* private routine to assemble a proper file name                             */
  690. /*----------------------------------------------------------------------------*/
  691. void AssembleName(char *where)
  692. {
  693.   CONTEXT *cp;
  694.  
  695.   cp = current_context;
  696.   AssemblePath(where);
  697.   if ( (cp->path) && (strcmp(cp->path, achBACKSLASH) != 0) )
  698.     strcat (where, achBACKSLASH);
  699.   strcat(where, namespec);
  700. }
  701.  
  702. /*----------------------------------------------------------------------------*/
  703. /* private routine to assemble a proper path name                             */
  704. /*----------------------------------------------------------------------------*/
  705. void AssemblePath(char *where)
  706. {
  707.   char *p;
  708.  
  709.   p = where;
  710.   *p = '\0';
  711.   if (drivespec)
  712.     {
  713.       *p++ = drivespec;
  714.       *p++ = chCOLON;
  715.     }
  716.   if (current_context->path)
  717.     strcpy(p, current_context->path);
  718.   else
  719.     *p = '\0';
  720. }
  721.  
  722. /*----------------------------------------------------------------------------*/
  723. /* Private routine to                                                         */
  724. /* match two strings: both may be ambiguous in the DOS (OS/2) sense:          */
  725. /* using a question mark for a place holder, and a * to mean "up to           */
  726. /* the next dot"                                                              */
  727. /*----------------------------------------------------------------------------*/
  728.  
  729. /* returns 1 for match, 0 for not */
  730.  
  731. #define NEXTDOT(p) for(; *p && (*p != '.'); p++)
  732. #define MATCH   1
  733. #define NOMATCH 0
  734.  
  735. wcmatch(char *string1, char *string2)
  736. {
  737.    char *p, *q;
  738.  
  739.    if (!strcmp(string1, allfs) || !strcmp(string2, allfs))
  740.      return(MATCH);
  741.    if (!strcmp(string1, "*")   || !strcmp(string2, "*"))
  742.      return(MATCH);
  743.    for (p = string1, q = string2;
  744.         *p && *q;
  745.         p++, q++)
  746.      {
  747.        if ((*p == '?') || (*q == '?'))
  748.          continue;
  749.        else
  750.          if ((*p == '*') || (*q == '*'))
  751.            {
  752.              NEXTDOT(p); NEXTDOT(q);
  753.              if (!*p && !*q)
  754.                return(MATCH);
  755.              else
  756.                if (!*p || !*q)
  757.                  return(NOMATCH);
  758.            }
  759.          else
  760.            if (toupper(*p) != toupper(*q))
  761.              return(NOMATCH);
  762.      }
  763.      if (toupper(*p) == toupper(*q))
  764.        return(MATCH);
  765.      else
  766.        if (*p == '*')
  767.          NEXTDOT(p);
  768.        else
  769.          if (*q == '*')
  770.            NEXTDOT(q);
  771.        if (toupper(*p) == toupper(*q))
  772.          return(MATCH);
  773.      return(NOMATCH);
  774. }
  775.  
  776. #ifdef DBGMAIN
  777.  
  778. #define FSFTEST
  779. #include "fmf.h"
  780. #include <process.h>
  781. #include <stddef.h>
  782. #define STACKSIZE 4096
  783. ULONG ctrSem = 0;
  784. int   ctr = 0;
  785.  
  786.  
  787. main(argc, argv, envp)
  788.    int argc;
  789.    char *argv[];
  790.    char *envp[];
  791. {
  792.  
  793.    int attr, maxthreads, rc;
  794.    void dir(char *spec);
  795.    char name[CCHMAXPATH];
  796.  
  797.    if (argc < 2)
  798.      {
  799.       printf("\nTest scaffold for FindMatchingFile routines\n");
  800.       printf("invoke as foo filespec filespec filespec...\n");
  801.       return(0);
  802.      }
  803.  
  804.    maxthreads = fmf_query_max_threads();
  805.    printf("\nNumber of threads supported is %d.\n", maxthreads);
  806.  
  807.  
  808.    printf("WITH THE MODEFLAG SET TO 0\n");
  809.    if ( (rc = fmf_init(argv[1], FILE_HIDDEN | FILE_DIRECTORY | FILE_SYSTEM, 0)
  810.                                                                   != NO_ERROR) )
  811.      printf("Thread 1: fmf_init failed, rc = %d\n", rc);
  812.    else
  813.      while (rc == NO_ERROR)
  814.        {
  815.          rc = fmf_return_next(name, &attr);
  816.          if (rc == NO_ERROR)
  817.            printf("%s\n", name);
  818.        }
  819.  
  820.    printf("WITH THE MODEFLAG SET TO 0\n");
  821.    if ( (rc = fmf_init(argv[1], FILE_HIDDEN | FILE_DIRECTORY | FILE_SYSTEM, 1)
  822.                                                                   != NO_ERROR) )
  823.      printf("Thread 1: fmf_init failed, rc = %d\n", rc);
  824.    else
  825.      while (rc == NO_ERROR)
  826.        {
  827.          rc = fmf_return_next(name, &attr);
  828.          if (rc == NO_ERROR)
  829.            printf("%s\n", name);
  830.        }
  831.  
  832. }
  833.  
  834. #endif
  835.